<template>
  <div
    ref="editorRef"
    class="editor"
    @dragenter="handleDragenter"
    @dragover="handleDragover"
    @dragleave="handleDragleave"
    @drop="handleDrop"
    @click="clearCurComponent"
    @contextmenu.prevent.stop="showMenu($event, null)"
    :tabindex="-1"
    @keydown.ctrl.67="shortcut"
    @keydown.ctrl.86="shortcut"
    @keydown.ctrl.68="shortcut"
    @keydown.ctrl.88="shortcut"
  >
    <components
      v-for="(item, i) in componentData"
      :key="item.id"
      :is="item.component"
      :style="{ ...item.style, 'z-index': i + 1 }"
      :propValue="item.propValue"
      @mousedown.native="handleMousedown($event, item)"
      @click.native="setCur($event, item)"
      :class="[
        item.isCurrent || item.isCompose ? 'isCur' : '',
        item.islock ? '' : 'move',
      ]"
      @contextmenu.native.prevent.stop="showMenu($event, item)"
    ></components>
    <ContextMenu v-if="menuShow"></ContextMenu>
  </div>
</template>

<script>
import { mapMutations, mapState } from "vuex";
import { list } from "@/components/component-list.js";
import { formatStyle } from "@/utils/style.js";
import _ from "lodash";
import ContextMenu from "./ContextMenu.vue";
import bus from "@/utils/eventBus";
import { listenEditorKeydown } from "@/utils/shortcutKey.js";
import { calculatePosition } from "@/utils/calculate.js";

export default {
  components: {
    ContextMenu,
  },
  data() {
    return {
      existIds: [],
      nextId: 0,
      editorPosition: {
        top: 0,
        left: 0,
      },
    };
  },
  methods: {
    ...mapMutations([
      "setCurComponent",
      "addComponent",
      "saveHistoryState",
      "showContextMenu",
      "hideContextMenu",
      "addCurComponent",
      "clearcurComponentList",
    ]),
    setExistId(componentList) {
      componentList.forEach((item) => {
        if (item.component == "Group") {
          this.setExistId(item.propValue);
        }
        this.existIds.push(item.id);
      });
    },
    getId() {
      while (1) {
        this.nextId++;
        if (this.existIds.indexOf(this.nextId) == -1) {
          break;
        }
      }
    },
    giveNewId(component) {
      if (component.component == "Group") {
        component.propValue.forEach((item) => {
          this.giveNewId(item);
        });
      }
      component.id = this.nextId;
      this.getId();
    },
    handleDragenter(e) {
      e.dataTransfer.dropEffect = "move";
    },
    handleDragover(e) {
      e.preventDefault();
    },
    handleDragleave(e) {
      e.dataTransfer.dropEffect = "none";
    },
    handleDrop(e) {
      let style = {
        top: e.offsetY,
        left: e.offsetX,
      };
      let index = e.dataTransfer.getData("index");
      let component = list[index];
      let mycomponent = _.cloneDeep(component);
      mycomponent.style = formatStyle({ ...mycomponent.style, ...style });
      mycomponent.id = this.nextId;
      this.getId();
      mycomponent.islock = false;
      // 记录每个组件在画布中的位置
      let position = calculatePosition(mycomponent);
      mycomponent.position = position;
      this.addComponent(mycomponent);
      this.setCurComponent(mycomponent);
      this.saveHistoryState();
    },
    handleMousedown(e, component) {
      e.stopPropagation();
      let startY = parseInt(component.style.top);
      let startX = parseInt(component.style.left);
      let { x, y } = e;
      var timer = null;
      const move = (e) => {
        if (timer) return;
        timer = setTimeout(() => {
          let style = {
            top: `${e.y - y + startY}px`,
            left: `${e.x - x + startX}px`,
          };
          component.style = formatStyle({ ...component.style, ...style });
          timer = null;
        }, 16);
      };

      let lock = false; // 区别click和mouseup事件的锁
      let firstTime = new Date().getTime();
      const up = () => {
        let lastTime = new Date().getTime();
        if (lastTime - firstTime > 100) {
          lock = true;
        }
        if (lock) this.saveHistoryState();

        let position = calculatePosition(component);
        component.position = position;
        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", up);
      };

      if (component.islock == false) {
        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", up);
      }
    },
    setCur(e, component) {
      e.stopPropagation();
      if (e.ctrlKey && component != null) {
        component.isCompose = true;
        this.addCurComponent(component.id);
      } else {
        // 清除预备组合的组件状态
        this.clearcurComponentList();
      }
      this.hideContextMenu();
      this.setCurComponent(component);
    },
    clearCurComponent(e) {
      this.setCur(e, null);
    },
    showMenu(e, component) {
      if (component == null) {
        this.setCur(e, null);
        var position = {
          top: e.offsetY,
          left: e.offsetX,
        };
      } else {
        this.setCur(e, component);
        var position = {
          top: e.offsetY + parseInt(component.style.top),
          left: e.offsetX + parseInt(component.style.left),
        };
      }
      this.showContextMenu(position);
    },
    shortcut(e) {
      listenEditorKeydown(e);
    },
  },
  computed: {
    ...mapState(["curComponent", "componentData", "menuShow"]),
  },
  created() {
    this.saveHistoryState();
    this.setExistId(this.componentData);
    this.getId();
    bus.$on("paste", (component) => {
      this.giveNewId(component);
      this.addComponent(component);
      this.setCurComponent(component);
      this.saveHistoryState();
    });
    bus.$on("createImg", (val) => {
      const newImg = {
        component: "VImg",
        label: "图片",
        propValue: {
          src: val.src,
          fit: "fill",
        },
        icon: "picture-outline",
        isCurrent: false,
        isCompose: false,
        request: {},
        style: {
          width: val.width,
          height: val.height,
          borderRadius: "",
          top: 0,
          left: 0,
        },
        events: {},
      };

      newImg.id = this.nextId;
      this.getId();
      newImg.style = formatStyle(newImg.style);
      newImg.islock = false;

      this.addComponent(newImg);
      this.setCurComponent(newImg);
      this.saveHistoryState();
    });
  },
  mounted() {
    let top = this.$refs.editorRef.offsetTop;
    let left = this.$refs.editorRef.offsetLeft;
    this.editorPosition.top = top;
    this.editorPosition.left = left;
  },
};
</script>

<style lang="less" scoped>
.editor {
  position: relative;
  overflow: hidden;
  height: 100%;
  border: 0;
  outline: none;
}
.isCur {
  //   border: 2px solid red !important;
  outline: red solid 2px;
}
.move {
  cursor: move;
}
</style>
